home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Skunkware 5
/
Skunkware 5.iso
/
src
/
X11
/
xpaint-2.1.1
/
sprayOp.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-06-21
|
8KB
|
361 lines
/* +-------------------------------------------------------------------+ */
/* | Copyright 1992, 1993, David Koblas (koblas@netcom.com) | */
/* | | */
/* | Permission to use, copy, modify, and to distribute this software | */
/* | and its documentation for any purpose is hereby granted without | */
/* | fee, provided that the above copyright notice appear in all | */
/* | copies and that both that copyright notice and this permission | */
/* | notice appear in supporting documentation. There is no | */
/* | representations about the suitability of this software for | */
/* | any purpose. this software is provided "as is" without express | */
/* | or implied warranty. | */
/* | | */
/* +-------------------------------------------------------------------+ */
#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>
#include <X11/cursorfont.h>
#include <X11/Xos.h>
#include <sys/time.h>
#include "xpaint.h"
#include "Paint.h"
#include <math.h>
#include "misc.h"
#ifndef NOSTDHDRS
#include <stdlib.h>
#include <unistd.h>
#endif
typedef struct {
Widget w;
int useGauss;
int x, y;
XtIntervalId id;
Boolean gcFlag, isTiled, trackDrawn, drawing;
int lastX, lastY;
int zoom;
/*
** Borrowed from the info
*/
GC gc, gcx;
Pixmap drawable;
Boolean isFat;
} LocalInfo;
static int radius = 10, density = 10, radius2 = 10 * 10, rate = 100;
static Boolean style = True;
/*
** By default everything uses drand48(),
** I was making more exceptions than inclusinsion.
*/
#define USE_DRAND
#if defined(SVR4) || defined(__osf__)
#define SHORT_RANGE
#else
#ifndef random
long random(void);
#endif
#if !defined(sco)
int srandom(unsigned int);
#endif
#endif
#ifdef USE_DRAND
# ifdef random
# undef random
# undef srandom
# endif
# define srandom srand48
# define RANDOM(s, f) (drand48() * (f - s) + s)
#else
# ifdef SHORT_RANGE
# define RANGE 0x00000fff
# else
# define RANGE 0x0fffffff
# endif
# define RANDOM(s, f) (((double)(random() % RANGE) / (double)RANGE) * (f - s) + s)
#endif
static void gauss(int range, int *x, int *y)
{
float fac, r, v1, v2;
do {
v1 = RANDOM(-1.0, 1.0);
v2 = RANDOM(-1.0, 1.0);
r = v1 * v1 + v2 * v2;
} while (r >= 1.0);
fac = -2.0 * log(r) / r;
if (fac <= 0.0)
fac = 0.0;
else
fac = sqrt(fac) / 2.0;
*x = (v1 * fac) * range;
*y = (v2 * fac) * range;
}
static void draw(LocalInfo *l)
{
int i;
XRectangle rect;
union {
XSegment s[512];
XPoint p[512];
} p;
UndoGrow(l->w, l->x - radius, l->y - radius);
UndoGrow(l->w, l->x + radius, l->y + radius);
for (i = 0; i < density; i++) {
int rx, ry;
do {
if (l->useGauss) {
gauss(radius, &rx, &ry);
} else {
rx = RANDOM(-radius, radius);
ry = RANDOM(-radius, radius);
}
} while (rx * rx + ry * ry > radius2);
if (l->isTiled) {
p.s[i].x1 = l->x + rx;
p.s[i].y1 = l->y + ry;
p.s[i].x2 = l->x + rx;
p.s[i].y2 = l->y + ry;
} else {
p.p[i].x = l->x + rx;
p.p[i].y = l->y + ry;
}
}
XYtoRECT(l->x - radius, l->y - radius,
l->x + radius, l->y + radius, &rect);
if (l->isTiled) {
XDrawSegments(XtDisplay(l->w), l->drawable, l->gc, p.s, density);
if (!l->isFat)
XDrawSegments(XtDisplay(l->w), XtWindow(l->w), l->gc, p.s, density);
} else {
XDrawPoints(XtDisplay(l->w), l->drawable, l->gc, p.p, density, CoordModeOrigin);
if (!l->isFat)
XDrawPoints(XtDisplay(l->w), XtWindow(l->w), l->gc, p.p, density, CoordModeOrigin);
}
PwUpdate(l->w, &rect, False);
}
static void drawEvent(LocalInfo *l)
{
draw(l);
l->id = XtAppAddTimeOut(XtWidgetToApplicationContext(l->w),
rate, (XtTimerCallbackProc)drawEvent, (XtPointer)l);
}
static void drawOutline(Widget w, LocalInfo *l, int x, int y, Boolean flag)
{
Display *dpy = XtDisplay(w);
Window window = XtWindow(w);
XArc arc;
arc.width = radius * l->zoom * 2;
arc.height = radius * l->zoom * 2;
arc.angle1 = 0;
arc.angle2 = 360 * 64;
if (l->trackDrawn) {
arc.x = l->lastX - radius * l->zoom;
arc.y = l->lastY - radius * l->zoom;
XDrawArcs(dpy, window, l->gcx, &arc, 1);
l->trackDrawn = False;
}
if (flag) {
arc.x = x - radius * l->zoom;
arc.y = y - radius * l->zoom;
XDrawArcs(dpy, window, l->gcx, &arc, 1);
l->lastX = x;
l->lastY = y;
l->trackDrawn = True;
}
}
static void press(Widget w, LocalInfo *l, XButtonEvent *event, OpInfo *info)
{
GC sgc;
int width, rule, rule2;
/*
** Check to make sure all buttons are up, before doing this
*/
if ((event->state & (Button1Mask|Button2Mask|Button3Mask|Button4Mask|Button5Mask)) != 0)
return;
l->x = event->x;
l->y = event->y;
l->useGauss = style;
l->drawing = True;
drawOutline(w, l, 0, 0, False);
UndoStartPoint(w, info, event->x, event->y);
l->drawable = info->drawable;
l->isFat = info->isFat;
XtVaGetValues(w, XtNlineWidth, &width,
XtNfillRule, &rule,
XtNlineFillRule, &rule2,
NULL);
if (!l->gcFlag)
l->gcFlag = (width != 0);
if (event->button == Button2) {
sgc = info->second_gc;
l->isTiled = (rule2 != FillSolid);
} else if (event->button == Button1) {
sgc = info->first_gc;
l->isTiled = (rule != FillSolid);
} else
return;
if (l->gcFlag) {
if (l->gc == None)
l->gc = XCreateGC(XtDisplay(w), info->drawable, 0, NULL);
XCopyGC(XtDisplay(w), sgc, ~GCLineWidth, l->gc);
} else {
l->gc = sgc;
}
if (l->id == (XtIntervalId)NULL)
drawEvent(l);
else
draw(l);
}
static void motion(Widget w, LocalInfo *l, XMotionEvent *event, OpInfo *info)
{
if (l->drawing && info->surface == opPixmap) {
l->x = event->x;
l->y = event->y;
draw(l);
} else if (!l->drawing && info->surface == opWindow) {
l->zoom = info->zoom;
drawOutline(w, l, event->x, event->y, True);
}
}
static void release(Widget w, LocalInfo *l, XButtonEvent *event, OpInfo *info)
{
int mask;
/*
** Check to make sure all buttons are up, before doing this
*/
mask = Button1Mask|Button2Mask|Button3Mask|Button4Mask|Button5Mask;
switch (event->button) {
case Button1: mask ^= Button1Mask; break;
case Button2: mask ^= Button2Mask; break;
case Button3: mask ^= Button3Mask; break;
case Button4: mask ^= Button4Mask; break;
case Button5: mask ^= Button5Mask; break;
}
if ((event->state & mask) != 0)
return;
if (l->id != (XtIntervalId)NULL)
XtRemoveTimeOut(l->id);
l->id = (XtIntervalId)NULL;
l->drawing = False;
}
static void leave(Widget w, LocalInfo *l, XEvent *event, OpInfo *info)
{
drawOutline(w, l, 0, 0, False);
}
/*
** Those public functions
*/
void SpraySetParameters(int r, int d, int sp)
{
radius = r;
radius2 = r * r;
density = d;
rate = sp * 10;
}
Boolean SprayGetStyle()
{
return style;
}
void SpraySetStyle(Boolean flag)
{
style = flag;
}
static void *commonSprayAdd(Widget w, Boolean flag)
{
LocalInfo *l = XtNew(LocalInfo);
static int inited = False;
if (!inited) {
srandom((int)time(0));
inited = True;
}
l->w = w;
l->id = (XtIntervalId)NULL;
l->gc = None;
l->gcx = GetGCX(w);
l->gcFlag = False;
l->useGauss = flag;
l->trackDrawn = False;
l->drawing = False;
XtVaSetValues(w, XtNcompress, False,
XtVaTypedArg, XtNcursor, XtRString, "spraycan", sizeof(Cursor), NULL);
OpAddEventHandler(w, opPixmap, ButtonPressMask, FALSE, (OpEventProc)press, l);
OpAddEventHandler(w, opWindow|opPixmap, PointerMotionMask, FALSE, (OpEventProc)motion, l);
OpAddEventHandler(w, opPixmap, ButtonReleaseMask, FALSE, (OpEventProc)release, l);
OpAddEventHandler(w, opWindow, LeaveWindowMask, FALSE, (OpEventProc)leave, l);
return l;
}
void *SprayAdd(Widget w)
{
return commonSprayAdd(w, style);
}
void SprayRemove(Widget w, LocalInfo *l)
{
OpRemoveEventHandler(w, opPixmap, ButtonPressMask, FALSE, (OpEventProc)press, l);
OpRemoveEventHandler(w, opWindow|opPixmap, PointerMotionMask, FALSE, (OpEventProc)motion, l);
OpRemoveEventHandler(w, opPixmap, ButtonReleaseMask, FALSE, (OpEventProc)release, l);
OpRemoveEventHandler(w, opWindow, LeaveWindowMask, FALSE, (OpEventProc)leave, l);
if (l->gcFlag)
XFreeGC(XtDisplay(w), l->gc);
if (l->id != (XtIntervalId)NULL)
XtRemoveTimeOut(l->id);
XtFree((XtPointer)l);
}
void *SmearAdd(Widget w)
{
return commonSprayAdd(w, False);
}
void SmearRemove(Widget w, LocalInfo *l)
{
SprayRemove(w, l);
}